package br.edu.ufc.deti.broker.descisao;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;

import br.edu.ufc.deti.beans.*;
import br.edu.ufc.deti.util.ResourceUtils;

public class NgcDescisao {

	private final String pathServer = "/home/antonio/workspace_helios/perfclusters";
	private final String FILE_NAME_PATH = "/application.properties";
	private PerfClusters perfClusters = new PerfClusters();
	
	public NgcDescisao(PerfClusters perfClusters){
		this.perfClusters = perfClusters;
	}
	
	/**
	 * 	Copia e executa os benchmarks escolhidos para/nos recursos escolhidos.
	 * Em seguida, após obter os resultados ordena os recursos de acordo com os
	 * melhores valores dos requisitos solicitados.
	 *  
	 * @return
	 */
	public PerfClusters ordenaRecursos(){
		try {
			Float pesoMemoria = null, pesoProc = null, pesoRedeInterna = null, pesoRedeExterna = null;

			// Calculando valor de desempenho mínimo exigido por a aplicação;
			for (Iterator<Requisito> i = perfClusters.getRequisitos().iterator(); i.hasNext();) {
				Requisito requisito = (Requisito) i.next();
				
				if(requisito.getDscRequisito().equalsIgnoreCase("processamento")){
					pesoProc = requisito.getUsoRequisito();
					perfClusters.getAplicacao().setValorProcessador( requisito.getValorMinimoRequisito() );
				}else if(requisito.getDscRequisito().equalsIgnoreCase("memoria")){
					pesoMemoria = requisito.getUsoRequisito();
					perfClusters.getAplicacao().setValorMemoria( requisito.getValorMinimoRequisito() );
				}else if(requisito.getDscRequisito().equalsIgnoreCase("rede_interna")){
					pesoRedeInterna = requisito.getUsoRequisito();
					perfClusters.getAplicacao().setValorRedeInterna( requisito.getValorMinimoRequisito() );
				}else if(requisito.getDscRequisito().equalsIgnoreCase("rede_externa")){
					pesoRedeExterna = requisito.getUsoRequisito();
					perfClusters.getAplicacao().setValorRedeExterna( requisito.getValorMinimoRequisito() );
				}
			}
			perfClusters.getAplicacao().setDesempenhoMinimo(pesoMemoria, pesoProc, pesoRedeInterna, pesoRedeExterna);
			
			// Calculando valor de desempenho dos recursos;
			for (Iterator<Recurso> i = perfClusters.getRecursos().iterator(); i.hasNext();) {
				Recurso recurso = (Recurso) i.next();
				for (Iterator<Requisito> j = perfClusters.getRequisitos().iterator(); j.hasNext();) {
					Requisito requisito = (Requisito) j.next();
					executaBenchmark(recurso, requisito.getDscRequisito());
				}
				recurso.setValorNota(pesoMemoria, pesoProc, pesoRedeInterna, pesoRedeExterna);
			}
			System.out.println("Ordenando recursos...");
			Collections.sort(perfClusters.getRecursos());
			
			if( perfClusters.getRecursos().get(0).getValorNota() < perfClusters.getAplicacao().getDesempenhoMinimo() ){
				Mensagem mensagem = new Mensagem( "erro", "Não dispomos de recurso apto para execução da aplicação" );
				perfClusters.getMensagens().add( mensagem );
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return perfClusters;
	}
	/**
	 * @param recurso
	 * @param requisito
	 * @throws IOException 
	 * @throws InterruptedException 
	 */
	private void executaBenchmark(Recurso recurso, String requisito) throws IOException, InterruptedException {
		String scriptExecucaoBench = criaArquivoExecucaoBenchmark(recurso, requisito), resultado = "";
		System.out.println("executando benchmark...:"+"/bin/sh "+scriptExecucaoBench);
		Process proc = Runtime.getRuntime().exec("/bin/sh "+scriptExecucaoBench);
		for (int i = 0; proc.waitFor() > 0; i++) {}
		if ( proc.waitFor() == 0 ) {
			BufferedReader in = new BufferedReader(new FileReader(pathServer+"/scripts/benchmark_"+requisito+"_result.txt"));
	        while (in.ready()) {resultado = in.readLine();}
	        in.close();

		    if(requisito.equalsIgnoreCase("processamento")){
				recurso.setValorProcessador(new Float(resultado));
			}else if(requisito.equalsIgnoreCase("memoria")){
				recurso.setValorMemoria(new Float(resultado));
			}else if(requisito.equalsIgnoreCase("rede_interna")){
				recurso.setValorRedeInterna(new Float(resultado));
			}else if(requisito.equalsIgnoreCase("rede_externa")){
				recurso.setValorRedeExterna(new Float(resultado));
			}
		}
	}
	public String criaArquivoExecucaoBenchmark(Recurso recurso, String requisito) throws IOException {
		String portRecurso = "22";
		String hostDestino = recurso.getHostRecurso();
		String pathScript = pathServer+"/scripts/benchmark_"+requisito+"_exec.sh";
		String userDestino = ResourceUtils.getInstance().getProperty( FILE_NAME_PATH, "USER_"+hostDestino );
		String tipoRecurso = ResourceUtils.getInstance().getProperty( FILE_NAME_PATH, "TYPE_"+hostDestino );

		FileWriter fw = new FileWriter(pathScript);
		fw.write("#!/bin/sh\n");
	
		if (tipoRecurso.equalsIgnoreCase("cenapadne")||tipoRecurso.equalsIgnoreCase("powercost")||tipoRecurso.equalsIgnoreCase("cesup")) {
			if( requisito.equalsIgnoreCase("rede_externa") ){ 		// iperf
				executaBenchmarkVazaoExterna(recurso, requisito, fw);
			}else if( requisito.equalsIgnoreCase("rede_interna") ){	// skampi
				executaBenchmarkVazaoInterna(hostDestino, userDestino, fw);
			}else{													// linpack e free -m 
				executaBenchmarkProcessamentoMemoria(requisito, hostDestino, userDestino, fw);
			}
		} else if (tipoRecurso.equalsIgnoreCase("uchicago")) {
			if( requisito.equalsIgnoreCase("rede_externa") ){
				executaBenchmarkVazaoExterna(recurso, requisito, fw);
			}else if( requisito.equalsIgnoreCase("rede_interna") ){
				executaBenchmarkVazaoInterna(hostDestino, userDestino, fw);
			}else{
				fw.write("scp -o StrictHostKeyChecking=no "+pathServer+"/build/classes/benchmark_"+requisito+".class "+userDestino+"@"+hostDestino+":/opt/benchmark_"+requisito+".class \n");
				fw.write("ssh -o StrictHostKeyChecking=no "+userDestino+"@"+hostDestino+" 'cd /opt \n ./java/jdk1.6.0_11/bin/java benchmark_"+requisito+"\' \n");
				fw.write("scp -o StrictHostKeyChecking=no "+userDestino+"@"+hostDestino+":/opt/benchmark_"+requisito+"_result.txt "+pathServer+"/scripts");
			}
		} else if (tipoRecurso.equalsIgnoreCase("eucalyptus")) {
			if( requisito.equalsIgnoreCase("rede_externa") ){
				executaBenchmarkVazaoExterna(recurso, requisito, fw);
			}else if( requisito.equalsIgnoreCase("rede_interna") ){
				executaBenchmarkVazaoInterna(hostDestino, userDestino, fw);
			}else{
				fw.write("scp -o StrictHostKeyChecking=no "+pathServer+"/build/classes/benchmark_"+requisito+".class "+userDestino+"@"+hostDestino+":/opt/benchmark_"+requisito+".class \n");
				fw.write("ssh -o StrictHostKeyChecking=no "+userDestino+"@"+hostDestino+" 'cd /opt \n ./java/jdk1.6.0_11/bin/java benchmark_"+requisito+"\' \n");
				fw.write("scp -o StrictHostKeyChecking=no "+userDestino+"@"+hostDestino+":/opt/benchmark_"+requisito+"_result.txt "+pathServer+"/scripts");
			}
		} 
		fw.close();
		return pathScript;
	}

	/**
	 * @param requisito  @param hostDestino @param userDestino @param fw
	 * @throws IOException
	 */
	private void executaBenchmarkProcessamentoMemoria(String requisito,	String hostDestino, String userDestino, FileWriter fw) throws IOException {
		String porta = hostDestino.equalsIgnoreCase("powercost.rcost.unisannio.it")?"34521":"22";
		
		fw.write("scp -P "+porta+" "+pathServer+"/build/classes/benchmark_"+requisito+".class "+userDestino+"@"+hostDestino+":~/benchmark_"+requisito+".class \n");
		fw.write("ssh "+userDestino+"@"+hostDestino+" -p "+porta+" 'java benchmark_"+requisito+"' \n");
		fw.write("scp -P "+porta+" "+userDestino+"@"+hostDestino+":~/benchmark_"+requisito+"_result.txt "+pathServer+"/scripts \n");
	}
	/**
	 * @param recurso @param requisito @param fw 
	 * @throws IOException
	 */
	private void executaBenchmarkVazaoExterna(Recurso recurso, String requisito, FileWriter fw) throws IOException {
		//fw.write("scp "+pathServer+"/benchmarks/vazao_rede/iperf-2.0.5.tar.gz "+userDestino+"@"+hostDestino+":~/iperf-2.0.5.tar.gz \n");
		//fw.write("gunzip -c iperf-2.0.5.tar.gz | tar -xvf -");
		//fw.write("cd iperf-2.0.5");
		//fw.write("./configure");
		//fw.write("make");
		//fw.write("make install");
		fw.write("cp "+pathServer+"/build/classes/benchmark_"+requisito+".class /home/antonio/benchmark_"+requisito+".class \n");
		fw.write("cd /home/antonio/\n java benchmark_"+requisito+" "+recurso.getIpRecurso()+" \n");
		fw.write("cp /home/antonio/benchmark_"+requisito+"_result.txt "+pathServer+"/scripts");
	}

	/**
	 * @param hostDestino @param userDestino @param fw
	 * @throws IOException
	 */
	private void executaBenchmarkVazaoInterna(String hostDestino, String userDestino, FileWriter fw) throws IOException {
		//fw.write("scp "+pathServer+"/benchmarks/vazao_cluster/skampi.tar.gz "+userDestino+"@"+hostDestino+":~/skampi.tar.gz \n");
		//fw.write("tar -vzxf skampi.tar.gz \n");
		//fw.write("make \n");
		fw.write("cd skampi-5.0.4-r0355 \n");
		fw.write("mpiexec -n 4 ./skampi -i foo.ski -o bar.sko \n");
		fw.write("scp "+userDestino+"@"+hostDestino+":~/skampi-5.0.4-r0355/bar.sko "+pathServer+"/scripts \n");
	}
}
